home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 19
/
Aminet 19 (1997)(GTI - Schatztruhe)[!][Jun 1997].iso
/
Aminet
/
text
/
misc
/
nroff.lha
/
nroff
/
macros.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-01-24
|
10KB
|
572 lines
/*
* macros.c - macro input/output processing for nroff word processor
*
* adapted for atariST/TOS by Bill Rosenkranz 11/89
* net: rosenkra@hall.cray.com
* CIS: 71460,17
* GENIE: W.ROSENKRANZ
*
* original author:
*
* Stephen L. Browning
* 5723 North Parker Avenue
* Indianapolis, Indiana 46220
*
* history:
*
* - Originally written in BDS C;
* - Adapted for standard C by W. N. Paul
* - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz
*/
#undef NRO_MAIN /* extern globals */
#include <stdio.h>
#include "nroff.h"
/*------------------------------*/
/* defmac */
/*------------------------------*/
defmac (p, infp)
register char *p;
FILE *infp;
{
/*
* Define a macro. top level, read from stream.
*
* we should read macro without interpretation EXCEPT:
*
* 1) number registers are interpolated
* 2) strings indicated by \* are interpolated
* 3) arguments indicated by \$ are interpolated
* 4) concealed newlines indicated by \(newline) are eliminated
* 5) comments indicated by \" are eliminated
* 6) \t and \a are interpreted as ASCII h tab and SOH.
* 7) \\ is interpreted as backslash and \. is interpreted as a period.
*
* currently, we do only 3. a good place to do it would be here before
* putmac, after colmac...
*/
register char *q;
register int i;
char name[MNLEN];
char defn[MXMLEN];
char newend[10];
/*
* skip the .de and get to the name...
*/
q = skipwd (p);
q = skipbl (q);
/*
* ok, name now holds the name. make sure it is valid (i.e. first
* char is alpha...). getwrd returns the length of the word.
*/
i = getwrd (q, name);
if (!isprint (*name))
{
fprintf (err_stream,
"***%s: missing or illegal macro definition name\n",
myname);
err_exit (-1);
}
/*
* truncate to 2 char max name.
*/
if (i > 2)
name[2] = EOS;
/*
* skip the name and see if we have a new end defined...
*/
q = skipwd (p);
q = skipbl (q);
for (i = 0; i < 10; i++)
newend[i] = EOS;
for (i = 0; (i < 10) && ( isalpha (q[i]) || isdigit (q[i]) ); i++)
{
newend[i] = q[i];
}
/*
* read a line from input stream until we get the end of macro
* command (.en or ..). actually. we should have read the next
* field just above here to get the .de NA . or .de NA en string
* to be new end of macro.
*/
i = 0;
while (getlin (p, infp) != EOF)
{
if (p[0] == dc.cmdchr && p[1] == '\\' && p[2] == '\"')
{
/*
* comment, ignore it
*/
continue;
}
if (p[0] == dc.cmdchr && newend[0] != EOS
&& p[1] == newend[0] && p[2] == newend[1])
{
/*
* replacement end found
*/
break;
}
if (p[0] == dc.cmdchr && p[1] == 'e' && p[2] == 'n')
{
/*
* .en found
*/
break;
}
if (p[0] == dc.cmdchr && p[1] == dc.cmdchr)
{
/*
* .. found
*/
break;
}
/*
* collect macro from the line we just read. all this does
* is put it in the string defn.
*/
if ((i = colmac (p, defn, i)) == ERR)
{
fprintf (err_stream,
"***%s: macro definition too long\n", myname);
err_exit (-1);
}
}
/*
* store the macro
*/
if (!ignoring)
{
if (putmac (name, defn) == ERR)
{
fprintf (err_stream,
"***%s: macro definition table full\n", myname);
err_exit (-1);
}
}
}
/*------------------------------*/
/* colmac */
/*------------------------------*/
colmac (p, d, i)
register char *p;
char *d;
register int i;
{
/*
* Collect macro definition from input stream
*/
char *pstart = p;
int istart = i;
while (*p != EOS)
{
/*
* are we over the length limit for a single macro?
*/
if (i >= MXMLEN - 1)
{
d[i - 1] = EOS;
return (ERR);
}
/*
* "i break for comments..."
*/
if (*p == '\\' && *(p+1) == '\"')
{
/*
* first back over any whitespace between comment
* start and last character in line. remember to
* decrement counter i, too...
*/
p--;
while (isspace (*p) && p > pstart && i > istart)
{
p--;
i--;
}
/*
* now skip over the comment until we reach the
* trailing newline
*/
while (*p != EOS)
{
if (*p == '\n' || *p == '\r')
break;
p++;
}
}
/*
* skip quoted things
*/
if (*p == '\\' && *(p+1) == '\\')
p++;
/*
* copy it
*/
d[i++] = *p++;
}
d[i] = EOS;
return (i);
}
/*------------------------------*/
/* putmac */
/*------------------------------*/
putmac (name, p)
char *name;
char *p;
{
/*
* Put macro definition into table
*
* NOTE: any expansions of things like number registers SHOULD
* have been done already.
*/
/*
* any room left? (did we exceed max number of possible macros)
*/
if (mac.lastp >= MXMDEF)
return (ERR);
/*
* will new one fit in big buffer?
*/
if (mac.emb + strlen (name) + strlen (p) + 1 > &mac.mb[MACBUF])
{
return (ERR);
}
/*
* add it...
*
* bump counter, set ptr to name, copy name, copy def.
* finally increment end of macro buffer ptr (emb).
*
* macro looks like this in mb:
*
* mac.mb[MACBUF] size of total buf
* lastp < MXMDEF number of macros possible
* *mnames[MXMDEF] -> names, each max length
* ..._____________________________...____________________...
* / / /|X|X|0|macro definition |0| / / / / / / /
* .../_/_/_|_|_|_|________________...___|_|/_/_/_/_/_/_/_...
* ^
* |
* \----- mac.mnames[mac.lastp] points here
*
* both the 2 char name (XX) and the descripton are null term and
* follow one after the other.
*/
++mac.lastp;
mac.mnames[mac.lastp] = mac.emb;
strcpy (mac.emb, name);
strcpy (mac.emb + strlen (name) + 1, p);
mac.emb += strlen (name) + strlen (p) + 2;
return (OK);
}
/*------------------------------*/
/* getmac */
/*------------------------------*/
char *getmac (name)
register char *name;
{
/*
* Get (lookup) macro definition from namespace
*/
register int i;
/*
* loop for all macros, starting with last one
*/
for (i = mac.lastp; i >= 0; --i)
{
/*
* is this REALLY a macro?
*/
if (mac.mnames[i])
{
/*
* if it compares, return a ptr to it
*/
if (!strcmp (name, mac.mnames[i]))
{
/*!!!debug puts (mac.mnames[i]);*/
if (mac.mnames[i][1] == EOS)
return (mac.mnames[i] + 2);
else
return (mac.mnames[i] + 3);
}
}
}
/*
* none found, return null
*/
return (NULL_CPTR);
}
/*------------------------------*/
/* maceval */
/*------------------------------*/
maceval (p, m)
register char *p;
char *m;
{
/*
* Evaluate macro expansion
*/
register int i;
register int j;
char *argp[15];
char c;
int xc;
/*
* replace command char with EOS
*/
*p++ = EOS;
/*
* initialize argp array to substitute command
* string for any undefined argument
*
* NO!!! this is fixed...
*/
/* for (i = 0; i < 10; ++i)
argp[i] = p;
*/
/*
* skip the command name
*/
p = skipwd (p);
*p++ = EOS;
/*
* loop for all $n variables...
*/
for (i = 0; i < 10; ++i)
{
/*
* get to substituted param and if no more, reset remaining
* args to NULL and stop. using "i" here IS ok...
*/
p = skipbl (p);
if (*p == '\r' || *p == '\n' || *p == EOS)
{
if (debugging)
fprintf (err_stream,
"***%s.maceval: set_ireg(.$, %d, 0)\n",
myname,i);
set_ireg (".$", i, 0);
for ( ; i < 10; i++)
{
argp[i] = NULL_CPTR;
}
break;
}
/*
* ...otherwise, see if this param is quoted. if it is,
* it is all one parameter, even with blanks (but not
* newlines...). look for another "c" (which is the quote).
*
* if no quote, just read the arg as a single word and null
* terminate it.
*/
if (*p == '\'' || *p == '"')
{
c = *p++;
argp[i] = p;
while (*p != c && *p != '\r' && *p != '\n' && *p != EOS)
++p;
*p++ = EOS;
}
else
{
argp[i] = p;
p = skipwd (p);
*p++ = EOS;
}
}
/*
* m contains text of the macro. p contained the input line.
* here we start at the end of the macro def and see if there
* are any $n thingies. go backwards.
*/
for (i = strlen (m) - 1; i >= 0; --i)
{
/*
* found a $.
*/
if (i > 0 && m[i - 1] == '$')
{
if (!isdigit (m[i]))
{
/*
* it wasn't a numeric replacement arg so
* push this char back onto input stream
*/
putbak (m[i]);
}
else
{
/*
* it WAS a numeric replacement arg. so we
* want to push back the appropriate macro
* invocation arg. m[i]-'0' is the numerical
* value of the $1 thru $9. if the arg is
* not there, argp[n] will be (char *) 0
* and pbstr will do nothing.
*/
xc = m[i] - '1';
if (argp[xc])
pbstr (argp[xc]);
--i;
}
}
else
{
/*
* no $ so push back the char...
*/
putbak (m[i]);
}
}
/*
* at this point, the iobuf will hold the new macro command, full
* expanded for $n things. the return gets us right back to the
* main loop in main() and we parse the (new) command just as if
* it were read from a file.
*/
}
/*------------------------------*/
/* printmac */
/*------------------------------*/
printmac (opt)
int opt; /* 0=name&size,1=total size,2=full */
{
/*
* print all macros and strings and tabulate sizes
*/
register int i; /* was long, minix needs int */
register long space;
register long totalspace;
register char *pname;
register char *pdef;
space = 0L;
totalspace = 0L;
fflush (out_stream);
fflush (err_stream);
for (i = mac.lastp; i >= 0; --i)
{
/*
* is this REALLY a macro?
*/
if (mac.mnames[i])
{
pname = (char *) (mac.mnames[i]);
pdef = pname + 3;
if (*(pname + 1) == '\0')
pdef = pname + 2;
space = (long) strlen (pdef);
totalspace += space;
switch (opt)
{
case 0:
fprintf (err_stream, "%s %ld\n", pname, space);
break;
case 2:
fprintf (err_stream, "%s %ld\n", pname, space);
fprintf (err_stream, "%s\n", pdef);
break;
case 1:
default:
break;
}
}
}
fprintf (err_stream, "Total space: %ld\n", totalspace);
}